package br.senac.arqpad.pizzaria.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import br.senac.arqpad.pizzaria.model.ClasseComId;
import br.senac.arqpad.pizzaria.model.Repository;


public abstract class DAOJDBC<T> implements Repository<T>  {

	public DAOJDBC() {
		super();
	}

	@Override
	public List<T> getLista() {
		return listarTodos();
	}

	@Override
	public List<T> listarTodos() {
	
		try			
		{
			
			DBUtil db = DBUtil.getInstance();
			Connection connection = db.getConnection();
										
			PreparedStatement preparedStatement = connection.prepareStatement(obterQueryListarTodos());
			
			ResultSet rs = preparedStatement.executeQuery();
					
			// Cria objeto de Lista
			List<T> lista = new ArrayList<T>();
	
			// Direciona o ResultSet para o primeiro registro
			while(rs.next())
			{
				T item = montaObjeto(rs);
				lista.add(item);
			}
	
			// Termina o resultset e o statement
			rs.close();			
			preparedStatement.close();
			connection.close();
	
			// Retorna a lista
			return lista;		
		}
		catch(SQLException e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	@Override
	public boolean incluir(T item) {
		
		int numeroRegistrosAfetados;
		
		try {
	
			DBUtil db = DBUtil.getInstance();
			Connection connection = db.getConnection();
	
			PreparedStatement preparedStatement = connection.prepareStatement(obterQueryInsert());
			
			preparedStatement = preencheParametrosInsert(item, preparedStatement);
	
			preparedStatement.execute();
			numeroRegistrosAfetados = preparedStatement.getUpdateCount();
			preparedStatement.close();
			connection.close();
	
			return numeroRegistrosAfetados == 1;
		
		}			
		catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	@Override
	public boolean atualizar(T item) {
		
		int numeroRegistrosAfetados;
		
		try {
	
			DBUtil db = DBUtil.getInstance();
			Connection connection = db.getConnection();
	
			PreparedStatement preparedStatement = connection.prepareStatement(obterQueryUpdate());
			
			preencheParametrosUpdate(item, preparedStatement);

			preparedStatement.execute();
			numeroRegistrosAfetados = preparedStatement.getUpdateCount();
			preparedStatement.close();
			connection.close();
	
			return numeroRegistrosAfetados == 1;
		
		}			
		catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}


	@Override
	public boolean excluir(T item) {
		
		int numeroRegistrosAfetados;
		
		try {
	
			DBUtil db = DBUtil.getInstance();
			Connection connection = db.getConnection();
	
			PreparedStatement preparedStatement = connection.prepareStatement(obterQueryDelete());
			
			preencheParametrosObter(item, preparedStatement);
	
			preparedStatement.execute();
			numeroRegistrosAfetados = preparedStatement.getUpdateCount();
			preparedStatement.close();
			connection.close();
	
			return numeroRegistrosAfetados == 1;
		
		}			
		catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public T obter(ClasseComId i) {
	
		try			
		{
			
			DBUtil db = DBUtil.getInstance();
			Connection connection = db.getConnection();
										
			PreparedStatement preparedStatement = connection.prepareStatement(obterQueryObter());
			

			T item = null;
			
			preencheParametrosObter(item, preparedStatement);
			
			ResultSet rs = preparedStatement.executeQuery();

			item = null;
			
			// Direciona o ResultSet para o primeiro registro
			if (rs.next())
			{
				item = montaObjeto(rs);
			}
	
			// Termina o resultset e o statement
			rs.close();			
			preparedStatement.close();
			connection.close();
	
			// Retorna a lista
			return item;		
		}
		catch(SQLException e) {
			throw new RuntimeException(e.getMessage());
		}	
	}

	protected abstract String obterQueryListarTodos();
	protected abstract String obterQueryObter();
	protected abstract String obterQueryUpdate();
	protected abstract String obterQueryDelete();
	protected abstract String obterQueryInsert();
	protected abstract PreparedStatement preencheParametrosObter(T item,
			PreparedStatement preparedStatement) throws SQLException;
	protected abstract T montaObjeto(ResultSet rs) throws SQLException;
	protected abstract PreparedStatement preencheParametrosInsert(T item,
			PreparedStatement preparedStatement) throws SQLException; 
	protected abstract PreparedStatement preencheParametrosUpdate(T item,
			PreparedStatement preparedStatement) throws SQLException;

	
}